﻿module EmitGenerator

open Ast
open SymbolTableTypes
open EmitConverter
open EmitType

  let mutable private label_c = 0
  let mutable private while_c = 0

let private generate_class (Ast.ClassDecl(name, _, ``(f | m)s``)) (class_symbol : ClassTable) (optimized : bool) = 
  name, 
  ``(f | m)s`` |> Seq.filter(fun f_or_m -> f_or_m.IsField) 
               |> Seq.map(fun (Ast.FieldOrMethodDecl.FieldDecl (_,id,ids, _)) -> id :: ids)
               |> Seq.concat
               |> Seq.toList,
  ``(f | m)s`` |> Seq.filter(fun f_or_m -> f_or_m.IsMethod) 
               |> Seq.map(fun (FieldOrMethodDecl.MethodDecl (_, name, _, block, _)) ->
                              let (_, _, meth_symbol) = class_symbol.Methods.[name].Infos
                              
                              let env = makeLIR block meth_symbol.Value.Value label_c while_c
                              if optimized then
                                do EmitOptimizer.optimize_emit env.Emit

                              do label_c <- env.L_counter
                              do while_c <- env.While_counter
                              
                              let args = env.T_Symbols |> Seq.filter(fun t -> t.IsArg)
                                                       |> Seq.mapi(fun i t -> 
                                                                      do t.Id <- i 
                                                                      t)
                                                       |> Seq.toList
                              let temp = env.T_Symbols |> Seq.filter(fun t -> not t.IsArg)
                                                       |> Seq.mapi(fun i t -> 
                                                                      do t.Id <- i 
                                                                      t)
                                                       |> Seq.toList
                              (name, args, temp, env.Emit |> Seq.toList))
               |> Seq.toList
                

              
let generate_emit (p : Ast.Program) (symbols : GlobalSymbols) (optimized : bool) : (ClassName * ClassFields * ClassMethods ) list  =
  for (ClassDecl (name, _, _) as class_decl) in p do
    do EmitEnvironment.make_dispatch_vector symbols.[name]
    do EmitEnvironment.make_object_layout symbols.[name]
  let emits = ResizeArray()

  for (ClassDecl (name, _, _) as class_decl) in p do
    do emits.Add (generate_class class_decl symbols.[name] optimized)
//  seq{
//    for (ClassDecl (name, _, _) as class_decl) in p do
//      yield generate_class class_decl symbols.[name]
  emits |> Seq.toList 

    